﻿using System.Collections.Generic;
using System.Net;

public class UDPClientsManager2 :  IGameLifeCycle
{
    public const byte PingByte = 1;

    public IClientsManagerListener listener { get; set; }

    /// <summary>
    /// 所有客户端
    /// </summary>
    protected AtomDictionary<long, Remote> clientList = new AtomDictionary<long, Remote>();
    

    /// <summary>
    /// 当前待分配的客户端ID
    /// </summary>
    protected long m_CurClientId;
    

    /// <summary>
    /// 获取当前clientID
    /// </summary>
    /// <returns></returns>
    protected long GetCurClientId()
    {
        return System.Threading.Interlocked.Increment(ref m_CurClientId);
    }

    public void AddClient(long userId, Remote remote)
    {
        GameDebug.Log($"AddClient   userId:{userId}  remote:{remote.clientId}");
        this.clientList[userId] = remote;
    }
    
    
    //监听端口15001-16000
    const int portBegin = 15001;

    Queue<int> canUsePortQueue = new Queue<int>();
    int m_AddPortIndex;
    

    /// <summary>
    /// 获取可用端口
    /// </summary>
    /// <returns></returns>
    int GetCanUsePort()
    {
        int curPort = 0;

        lock (canUsePortQueue)
        {
            if (canUsePortQueue.Count <= 0)
            {
                //每次进10个端口待用
                int addCount = 10;
                int addPortBegin = portBegin + m_AddPortIndex * addCount;

                for (int i = addPortBegin; i < addPortBegin + addCount; i++)
                {
                    canUsePortQueue.Enqueue(i);
                }
                m_AddPortIndex++;
            }

            curPort = canUsePortQueue.Dequeue();
        }
        GameDebug.Log($"获取当前可用端口：{curPort}");

        return curPort;
    }
    /// <summary>
    /// 回收端口
    /// </summary>
    /// <param name="port"></param>
    void RecyclePort(int port)
    {
        lock (canUsePortQueue)
        {
            canUsePortQueue.Enqueue(port);
        }
    }


    public UDPClientsManager2()
    {

    }
    


    public UDPClient OnNewClientConnected(long userId)
    {
        UDPSocketServer connectScoketServer = new UDPSocketServer();

        UDPClient newClient = NewUDPClient(GetCurClientId(), null, connectScoketServer);
        newClient.userID = userId;

        newClient.BeginReceive(GetCanUsePort());
        newClient.onDisconnect = this.OnRemoveDisconnet;

        this.AddClient(userId, newClient);

        GameDebug.Log($"新用户上线:{newClient.ipEndPoint} connect socket:{connectScoketServer.socket?.GetHashCode()}  clientId:{newClient.clientId} \n dict:{clientList.dictionary.GetDictStr()}");

        this.listener.OnNewClient(newClient);

        return newClient;

        //udpSocketServer.SendTo(endPoint, new byte[] { 8 });
    }

    protected virtual UDPClient NewUDPClient(long clientId, EndPoint endPoint, UDPSocketServer uDPSocketServer)
    {
        return new UDPClient(clientId, (IPEndPoint)endPoint, uDPSocketServer);
    }


    public void RemoveClient(long userId)
    {
        if(userId < 0)
        {
            return;
        }

        Remote remote;
        this.clientList.TryGetValue(userId, out remote);

        if (remote != null)
        {
            UDPClient udpClient = remote as UDPClient;

            GameDebug.LogShowy($"移除客户端连接：{remote.ipEndPoint}");

            if (udpClient != null)
            {
                //int toRecyclePort = udpClient.listenPort;

                udpClient.Disconnect();

                this.RecyclePort(udpClient.listenPort);
            }
            else
            {
#if DEBUG
                GameDebug.LogError($"remote == null:{remote == null}   {remote?.GetType().Name}");
#endif
            }

            clientList.Remove(userId);
        }
        else
        {
#if DEBUG
            GameDebug.LogError($"RemoveClient cannot find userId:{userId}  clientList:{this.clientList.dictionary.GetDictStr()}");
#endif
        }
    }

    /// <summary>
    /// 有客户端断开连接
    /// </summary>
    /// <param name="rc"></param>
    protected virtual void OnRemoveDisconnet(EndPoint endPoint)
    {
        Remote toRemove = null;

        foreach(var client in this.clientList.Values)
        {
            if(client.ipEndPoint == endPoint)
            {
                toRemove = client;
            }
        }
        if (toRemove != null)
        {
            this.RemoveClient(toRemove.userID);

            this.listener?.OnDisConnect(toRemove);
        }
    }

    public  void Update(int frameCount)
    {

    }


}

